/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.tabbedproperties.section;

import java.util.List;

import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
import org.eclipse.uml2.uml.Constraint;
import org.eclipse.uml2.uml.Namespace;

import com.cea.papyrus.core.editpart.IUMLElementEditPart;
import com.cea.papyrus.core.tabbedproperties.PropertyViewSection;
import com.cea.papyrus.ocl.interpreter.OCLEditorComposite;
import com.cea.papyrus.tabbedproperties.composites.ConstraintsTableComposite;
import com.cea.papyrus.umlutils.Element;


/**
 * This class handles constraints property tab.
 * 
 * @author Chokri Mraidha
 */

public class ConstraintsSection extends PropertyViewSection {

	/**
	 * 
	 */
	public static int number=0;


	protected ConstraintsTableComposite constraintsTableComposite;

	/**
	 * 
	 */
	private Table table;

	/**
	 * 
	 */
	private org.eclipse.swt.widgets.Label separator;


	private Constraint selectedConstraint;

	/**
	 * 
	 */
	//private Text body = null;

	/**
	 * 
	 */
	private Button addButton, removeButton;

	/**
	 * 
	 */
	private MouseListener addButtonListener, removeButtonListener;

	/**
	 * 
	 */
	private SelectionListener tableListener;


	/**
	 * 
	 */

	private OCLEditorComposite oclEditorComposite;



	private TableViewer tableViewer;

	public ConstraintsSection() {
		tableListener = new ConstraintSelectionListener();
	}

	/**
	 * 
	 * 
	 * @param tabbedPropertySheetPage 
	 * @param parent 
	 */
	@Override
	public void createControls(Composite parent, TabbedPropertySheetPage tabbedPropertySheetPage) {
		super.createControls(parent, tabbedPropertySheetPage);
		// set a grid Layout
		GridLayout layout = new GridLayout();
		layout.numColumns = 2;
		layout.makeColumnsEqualWidth = false;
		layout.marginWidth = 0; // remove additional spaces
		layout.marginHeight = 0; // remove additional spaces
		parent.setLayout(layout);

		// table for Parameters
		constraintsTableComposite = new ConstraintsTableComposite(this);
		constraintsTableComposite.createContent(parent, tabbedPropertySheetPage.getWidgetFactory());
		GridData data = new GridData();
		data.grabExcessHorizontalSpace = false;
		data.grabExcessVerticalSpace = true;
		data.horizontalAlignment = SWT.FILL;
		constraintsTableComposite.setLayoutData(data);

		// table for the edition...
		oclEditorComposite = new OCLEditorComposite();
		oclEditorComposite.createContent(parent, tabbedPropertySheetPage.getWidgetFactory());
		data = new GridData();
		data.grabExcessHorizontalSpace = true;
		data.grabExcessVerticalSpace = true;
		data.horizontalAlignment = SWT.FILL;
		data.verticalAlignment = SWT.FILL;
		oclEditorComposite.setLayoutData(data);

		// add a listener on the table of the constraint composite to listen for the selected element
		constraintsTableComposite.addTableSelectionListener(tableListener);

//		super.createControls(parent, tabbedPropertySheetPage);
//		Composite composite = getWidgetFactory().createFlatFormComposite(parent);		
//		FormData data;
//		/* 
//		separator = getWidgetFactory().createSeparator(composite, SWT.VERTICAL);
//		separator.setVisible(false);
//		data = new FormData();
//		data.left = new FormAttachment(30);
//		data.top = new FormAttachment(0, 0);
//		data.bottom = new FormAttachment(90);
//		separator.setLayoutData(data);
//		*/
//		// 

//		// Decorated Table Composite to display constraint list


//		oclCompositeFactory = new OCLCompositeFactory(composite);

//		table = getWidgetFactory().createTable(composite, SWT.SINGLE | SWT.V_SCROLL | SWT.BORDER);
//		table.setHeaderVisible(true);

//		tableViewer = new TableViewer(table);				
//		tableViewer.setContentProvider(new ConstraintProvider());
//		TableViewerColumn columnViewer = new TableViewerColumn(tableViewer,SWT.NONE);
//		columnViewer.getColumn().setText("List of Constraints");
//		columnViewer.getColumn().setWidth(200);		
//		columnViewer.setLabelProvider(new ConstraintLabel());
//		columnViewer.setEditingSupport(new EditConstraintSupport(tableViewer, table));

//		//  tableViewer.setInput() is done in the refresh method

//		data = new FormData();
//		data.left = new FormAttachment(0, 0);
//		data.right = new FormAttachment(separator,-100);
//		data.bottom = new FormAttachment(100);
//		data.top = new FormAttachment(0, 0);
//		table.setLayoutData(data);
//		table.addSelectionListener(tableListener = new SelectionListener() {

//		public void widgetSelected(SelectionEvent e) {
//		updateConsoleSelection();
//		}

//		public void widgetDefaultSelected(SelectionEvent e) {
//		}
//		});



		// Add comment button

//		addButton = getWidgetFactory().createButton(composite, "Add...", SWT.PUSH);
//		addButton.setVisible(true);
//		data = new FormData();
//		data.right = new FormAttachment(separator, -10);
//		data.left = new FormAttachment(table, 10);
//		data.top = new FormAttachment(0, 0);
//		addButton.setLayoutData(data);

//		addButton.addMouseListener(addButtonListener = new MouseListener() {
//		public void mouseDoubleClick(MouseEvent e) {
//		}

//		public void mouseDown(MouseEvent e) {
//		}

//		public void mouseUp(MouseEvent e) {
//		if(getElement() != null) {
//		Constraint newConstraint = UMLFactory.eINSTANCE.createConstraint();
//		number = table.getSelection().length+1;
//		newConstraint.setName("Constraint_"+number);
//		number++;
//		newConstraint.getConstrainedElements().add(getElement());
//		((Namespace)getElement()).getOwnedRules().add(newConstraint);
//		OpaqueExpression constraintBody = UMLFactory.eINSTANCE.createOpaqueExpression(); 
//		constraintBody.getLanguages().clear();
//		constraintBody.getBodies().clear();
//		constraintBody.getLanguages().add("OCL");
//		constraintBody.setName("specification");
//		newConstraint.createSpecification("specification", null, UMLFactory.eINSTANCE.getUMLPackage().getOpaqueExpression());					
//		newConstraint.setSpecification(constraintBody);
//		refresh();
//		updateConsoleSelection();					
//		}
//		}
//		});


//		// Remove comment button

//		removeButton = getWidgetFactory().createButton(composite, "Remove...", SWT.PUSH);		
//		removeButton.setVisible(true);
//		data = new FormData();
//		data.right = new FormAttachment(separator, -10);
//		data.left = new FormAttachment(table, 10);
//		data.top = new FormAttachment(addButton, 5);
//		data.bottom = new FormAttachment(30);
//		removeButton.setLayoutData(data);

//		removeButton.addMouseListener(removeButtonListener = new MouseListener() {
//		public void mouseDoubleClick(MouseEvent e) {
//		}

//		public void mouseDown(MouseEvent e) {
//		}

//		public void mouseUp(MouseEvent e) {
//		if(getElement() != null) {
//		TableItem[] items = table.getSelection();
//		if (items.length > 0) {
//		((Namespace)getElement()).getOwnedRules().remove(items[0].getData());
//		}					
//		refresh();
//		}
//		}
//		});

		// Constraints description
		//oclConsole = new OCLConsoleComposite(composite, SWT.V_SCROLL, element);						
//		oclCompositeFactory.setConstraint(selectedConstraint);

//		data = new FormData();
//		data.left = new FormAttachment(separator, STANDARD_LABEL_WIDTH);
//		//data.right = new FormAttachment(100, 0);
//		data.top = new FormAttachment(0, 0);
//		data.bottom = new FormAttachment(90);
//		//console.setLayoutData(data);
		/*
		CLabel bodyLabel = getWidgetFactory().createCLabel(composite, "Specification:"); //$NON-NLS-1$		
		data = new FormData();
		data.right = new FormAttachment(composite,
				-ITabbedPropertyConstants.HSPACE);
		data.top = new FormAttachment(composite, 0, SWT.TOP);
		bodyLabel.setLayoutData(data);
		 */
	}

	/** @{inheritDoc} */
	@Override
	public void setInput(IWorkbenchPart part, ISelection selection) {
		super.setInput(part, selection);
		Assert.isTrue(selection instanceof IStructuredSelection);
		Object input = ((IStructuredSelection) selection).getFirstElement();
		if (input instanceof IUMLElementEditPart) {
			org.eclipse.uml2.uml.Element element = ((IUMLElementEditPart) input).getUmlElement();
			if(element instanceof org.eclipse.uml2.uml.Namespace) {
				Element utilsElement = new Element((org.eclipse.uml2.uml.Namespace)element);
				constraintsTableComposite.setElement(utilsElement);
				oclEditorComposite.setContext((Namespace)element);
				oclEditorComposite.setConstraint(null);
			}
		}
	}

	protected void updateConsoleSelection() {
		TableItem[] selected = constraintsTableComposite.getSelection();

		if ((selected.length == 0) || (selected[0] == null)) {			
			oclEditorComposite.setText("");
			oclEditorComposite.setConstraint(null);
		}else {
			selectedConstraint = (Constraint) selected[0].getData();
			String rule="";	
			if (selectedConstraint.getSpecification() != null) {
				rule = selectedConstraint.getSpecification().stringValue();
			}
			oclEditorComposite.setConstraint(selectedConstraint);
			// a constraint may only constrain one element
			// OCL: 06-05-01.pdf, p175
			oclEditorComposite.setText(rule);			
		}

	}
	private class ConstraintProvider implements  IStructuredContentProvider{

		public Object[] getElements(Object inputElement) {
			// TODO Auto-generated method stub
			return (Object[]) inputElement;			
		}

		public void dispose() {
			// TODO Auto-generated method stub

		}

		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
			// TODO Auto-generated method stub

		}


	}
	private class ConstraintLabel extends ColumnLabelProvider{
		public String getText(Object element) {
			return ((Constraint) element).getName();			
		}

	}
	private class EditConstraintSupport extends EditingSupport{
		public EditConstraintSupport(ColumnViewer viewer, Table table) {
			super(viewer);
			this.editor = new TextCellEditor(table);			
			// TODO Auto-generated constructor stub
		}

		private TextCellEditor editor;		

		@Override
		protected boolean canEdit(Object element) {
			// TODO Auto-generated method stub
			return true;
		}

		@Override
		protected CellEditor getCellEditor(Object element) {
			// TODO Auto-generated method stub
			return editor;
		}

		@Override
		protected Object getValue(Object element) {
			// TODO Auto-generated method stub
			return ((Constraint)element).getName();
		}

		@Override
		protected void setValue(Object element, Object value) {
			// TODO Auto-generated method stub
			((Constraint) element).setName((String) value);
			List<Constraint> ownedRules = ((Namespace)getElement()).getOwnedRules();
			tableViewer.setInput(ownedRules.toArray());
		}

	}

	/** @{inheritDoc} */
	@Override
	public void refresh() {
		constraintsTableComposite.refresh();
		oclEditorComposite.refresh();
	}

	/** @{inheritDoc} */
	@Override
	public void dispose(){
		super.dispose();
		if(constraintsTableComposite!=null) {
			constraintsTableComposite.dispose();
		}
		if(addButton!=null && !addButton.isDisposed())
			addButton.removeMouseListener(addButtonListener);
		if(removeButton!=null && !removeButton.isDisposed())
			removeButton.removeMouseListener(removeButtonListener);
		if (oclEditorComposite!=null)
			oclEditorComposite.dispose();
		/*
		if(body!=null && !oclConsole.isDisposed())
			body.removeFocusListener(bodyFocusListener);
		 */
	}

	/**
	 * Listener that listen for selection modification in the table of constraints 
	 */
	public class ConstraintSelectionListener implements SelectionListener {

		/** @{inheritDoc} */
		public void widgetSelected(SelectionEvent e) {
			Constraint selectedConstraint=null;
			
			//retrieve selection in the table composite
			if(oclEditorComposite!=null) {
				TableItem[] items = constraintsTableComposite.getSelection();
				if(items.length>0) {
					selectedConstraint = (Constraint)items[0].getData(constraintsTableComposite.KEY);
				} 
			}
			// refresh the ocl editor with the new constraint
			oclEditorComposite.setConstraint(selectedConstraint);
			oclEditorComposite.refresh();
		}

		/** @{inheritDoc} */
		public void widgetDefaultSelected(SelectionEvent e) {
			// Do nothing
		}
	}

}

